Skip to content

feat(nw-registered-agent): emit annualFeeUsd for ChittyFinance cost flow#21

Open
chitcommit wants to merge 1 commit into
feat/governance-scrapersfrom
feat/vendor-charge-extract
Open

feat(nw-registered-agent): emit annualFeeUsd for ChittyFinance cost flow#21
chitcommit wants to merge 1 commit into
feat/governance-scrapersfrom
feat/vendor-charge-extract

Conversation

@chitcommit

Copy link
Copy Markdown
Contributor

What

The nw-registered-agent scraper emitted documents + paymentStatus but no monetary amount, so a downstream cost consumer had nothing to book. Add a real annualFeeUsd field — the ChittyScrape side of the "ChittyScrape feeds the cost flow" wiring (ChittyFinance side: chittyapps/chittyfinance#134).

Changes

  • NWAgentResult.annualFeeUsd?: number — parsed from the account-page text via parseAnnualFee() (anchors on "registered agent"/"annual fee"/"renewal"/"service fee"/"yearly" + a $amount, thousands-aware).
  • Undefined when the portal shows no fee — never coerced to 0, so ChittyFinance's ingest can enforce its required-amount guard honestly.

Verification

parseAnnualFee exercised against realistic NW strings: extracts $125 / $1,250, returns undefined for fee-less inbox text and for $amounts with no fee anchor (no false positives). tsc --noEmit clean.

Credential-gated follow-up (chico/ChittyConnect)

The live scrape (NW login via ChittyConnect) is credential-gated; parseAnnualFee runs over real scraped text at runtime but can't be exercised end-to-end here without portal creds.

🤖 Generated with Claude Code

The nw-registered-agent scraper previously emitted documents + paymentStatus
but no monetary amount, so a downstream cost consumer had nothing to book.
Add a real annualFeeUsd field, parsed from the account-page text via
parseAnnualFee() (anchors on "registered agent"/"annual fee"/"renewal"/
"service fee" + a $amount). Undefined when the portal shows no fee — never
coerced to 0, so ChittyFinance's vendor-charge ingest can enforce its
required-amount guard honestly.

This is the ChittyScrape side of the "ChittyScrape feeds the cost flow"
wiring: registered-agent annual fee -> ChittyFinance expense (COA 5050).

parseAnnualFee verified against realistic NW strings: extracts $125 / $1,250,
returns undefined for fee-less inbox text and for $amounts lacking a fee
anchor (no false positives). tsc --noEmit clean.

NOTE: the live portal scrape is credential-gated (NW login via ChittyConnect);
parseAnnualFee runs over real scraped text at runtime but cannot be exercised
end-to-end here without portal creds — flagged as the chico/ChittyConnect
follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e5015939-7a13-4a17-81dc-e448d4ce09e8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/vendor-charge-extract

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e2b0cf4555

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +43 to +44
const money = /\$\s?([0-9]{1,3}(?:,[0-9]{3})*(?:\.[0-9]{2})?|[0-9]+(?:\.[0-9]{2})?)/;
for (const rawLine of text.split(/\n|\.|;/)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse full fee amounts before returning

When the portal shows an uncommaed four-digit fee or a fee with cents, this parser can emit a smaller amount than shown: the first regex alternative matches only the prefix of $1000 as $100, and text.split(/\n|\.|;/) splits $125.50 before the cents are parsed. Because annualFeeUsd is consumed as the booked cost amount, these common currency formats would silently understate the charge instead of returning the portal value.

Useful? React with 👍 / 👎.


// Best-effort parse of the annual fee from the account page text. Undefined
// when the portal view shows no fee — never coerced to 0.
const annualFeeUsd = parseAnnualFee(accountData?.bodySnippet || '');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid truncating the text used for fee extraction

This calls the fee parser on bodySnippet, but accountData only stores bodyText.slice(0, 2000). On a logged-in dashboard where navigation, banners, or entity lists push the billing/renewal section past the first 2000 characters, the new annualFeeUsd field will be omitted even though the page contains the fee, causing the downstream cost flow to see an unknown amount. Use the full page text, or a billing-specific extraction, for the new monetary field instead of the display snippet.

Useful? React with 👍 / 👎.

Comment on lines +44 to +47
for (const rawLine of text.split(/\n|\.|;/)) {
const line = rawLine.trim();
if (!anchors.test(line)) continue;
const m = line.match(money);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Match fee labels split from their amounts

This only checks for a dollar amount on the same split segment as the anchor, so common billing layouts such as a table/card with Annual Fee in one cell or line and $125 in the adjacent value cell/line return undefined. Since the scraper now exposes annualFeeUsd for the downstream cost flow, those label/value layouts will look like an unknown fee even though the portal surfaced the amount; the parser should inspect nearby text after an anchor rather than only the current line.

Useful? React with 👍 / 👎.

*/
export function parseAnnualFee(text: string): number | undefined {
if (!text) return undefined;
const anchors = /(registered\s+agent|annual\s+fee|renewal|service\s+fee|yearly)/i;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require the renewal amount to be for registered-agent service

Because renewal by itself is treated as a fee anchor, any dashboard line such as an annual-report renewal or other renewal notice with a $ amount will be returned as annualFeeUsd before a later registered-agent charge is considered. In accounts with annual report reminders or multiple renewal notices, this can book the wrong vendor-charge amount; the match needs to be scoped to registered-agent/service-fee billing text instead of any renewal line.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant